/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package callbackframework;


import com.sun.opengl.util.j2d.TextRenderer;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;
import objects.Primitive; 

/**
 *  I implemented a crude form of velocity to avoid speed of rotation relating directly to frame rate.
 *  Velocity is pretty important in games but not in an application like this. 
 *
 * @author rob
 */
public class StereoPairGLListener implements GLEventListener, KeyListener {

    private GLU glu;
    private StereoPairViewer top; //reference back to JFrame
    private int frameCount;
    private long secondsCounter; //used to count to 1 second
    private Primitive primitives; // class i added to contain simple 3d objects
    private GLUquadric quadric;

    private float xRotate;
    private float yRotate;
    private float zMoving;

    private boolean yLeft;
    private boolean yRight;
    private boolean xUp;
    private boolean xDown;
    private boolean zForward;
    private boolean zBackward;

    private boolean wireframeMode;

    private static float VELOCITY = 100; //100 degrees rotated per second

    private int x;
    private int y;
    private int width;
    private int height;

    private int fps;

    private double interocularDistance;
    private TextRenderer textRenderer;

    private int zFrontB = 20;

    private int zbackB = -20;
    

    

   

    public StereoPairGLListener(StereoPairViewer spv)
    {
        top = spv;
        frameCount = 0;
        secondsCounter = System.nanoTime();
        primitives = new Primitive();
        xRotate = -45.0f;
        yRotate = 45.0f;
        yLeft = false;
        yRight = false;
        xUp = false;
        xDown = false;

        wireframeMode = false;

        interocularDistance = 0.05;

        zForward = false;

        zBackward = false;

        zMoving = -10;

    }

    public Primitive getPrimitive()
    {
        return primitives;
    }

    public void init(GLAutoDrawable drawable) {
       GL gl = drawable.getGL();    /* don't make this gl a global! */
       glu = new GLU();    // this is okay as a global, but only use in callbacks
       quadric = glu.gluNewQuadric();
       drawable.addKeyListener(this);

       gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //black background
       primitives.setPrimitive("cube");
       gl.glEnable(GL.GL_DEPTH_TEST);
       gl.glDepthFunc(gl.GL_LEQUAL);

       gl.glHint(gl.GL_PERSPECTIVE_CORRECTION_HINT, gl.GL_NICEST); //render as nicely as possible and enable it
       gl.glEnable(gl.GL_PERSPECTIVE_CORRECTION_HINT);

       //gl.glEnable(gl.GL_LIGHTING);
       //gl.glEnable(gl.GL_LIGHT0);

       textRenderer = new TextRenderer(new Font("ARIAL", Font.PLAIN, 16), true, true);


       gl.setSwapInterval(1); //disable (0) sync with screen refresh rate

    }

    public void display(GLAutoDrawable drawable) {       



         frameCount++; //used to count everytime display is called in 1 second
         GL gl = drawable.getGL();
         gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        
         gl.glLoadIdentity(); //reset the drawing point so we dont get animation

         //handle wireframe mode
         if(wireframeMode)
         {
              gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_LINE );
         }
         else
         {
               gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_FILL );
         }

         //Rotation code written like this to avoid a 1 second delay and so that object
         //can be rotated in the x and y direction at the same time
         if(yLeft)
         {
            yRotate-=(VELOCITY/fps);
         }
         if(yRight)
         {
            yRotate+=(VELOCITY/fps);
         }
         if(xUp)
         {
            xRotate+=(VELOCITY/fps);
         }
         if(xDown)
         {
            xRotate-=(VELOCITY/fps);
         }

          if(zForward)

         {

            zMoving+=.10;



            if(zMoving >= zFrontB)

            {

                zMoving = zbackB;

            }

         }

         if(zBackward)

         {

            zMoving-=.10;



            if(zMoving <= zbackB)

            {

                zMoving = zbackB;

            }

         }

         //position virtual camera in viewport 1 or left viewport
         glu.gluLookAt(-interocularDistance, 0, zMoving, 0, 0, 0, 0, 1, 0);

         
         //rotate first viewport object
       
         //setup viewport 1
         gl.glViewport(x, y, width/2, height);  // size of drawing area

         gl.glMatrixMode(GL.GL_PROJECTION);
         gl.glLoadIdentity();

        

         glu.gluPerspective(45.0, ((float)width/2)/(float)height, 0.1, 100);    // fov, aspect ratio, near & far clipping planes
         gl.glMatrixMode(GL.GL_MODELVIEW);
        
         gl.glRotatef(xRotate, 1, 0, 0); //rotate 45 degrees in teh x axis
         gl.glRotatef(yRotate, 0, 1, 0); //y axis
        
        
         primitives.drawPrimitive(gl, glu, quadric); //draw object
       
        

         //viewport 2
         gl.glViewport(width/2, y, width/2, height);  // size of drawing area
         gl.glMatrixMode(GL.GL_PROJECTION);
         gl.glLoadIdentity();        
         glu.gluPerspective(45.0, ((float)width/2)/(float)height, 0.1, 100);    // fov, aspect ratio, near & far clipping planes
         gl.glMatrixMode(GL.GL_MODELVIEW);
         gl.glLoadIdentity();
       
         glu.gluLookAt(interocularDistance, 0, zMoving, 0, 0, 0, 0, 1, 0);
           //primitives.drawPlane(gl);
         gl.glRotatef(xRotate, 1, 0, 0); //rotate 45 degrees in teh x axis
         gl.glRotatef(yRotate, 0, 1, 0); //y axis
         
         primitives.drawPrimitive(gl, glu, quadric); //draw object
       
         

         gl.glViewport(x, y, width, height);  // size of drawing area
         gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_FILL ); //turn shading back on for text rendering in wireframe mode aswell
          textRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
         // optionally set the color
         textRenderer.setColor(1.0f, 1.0f, 1.0f, 1.0f);
         textRenderer.setSmoothing(false);
         if(interocularDistance < -.01)
         {
               textRenderer.draw("Interocular Distance: "+(Math.round(interocularDistance*10*2) + " (Pseudoscopic Viewing Mode)"), 20, 20);
         }
         else
         {
               textRenderer.draw("Interocular Distance: "+(Math.round(interocularDistance*10*2)), 20, 20);
         }
      
         textRenderer.endRendering();

         
         gl.glFlush();         

         calculateFPS();
              
    }

    /**
     * called when the window is resized
     * @param drawable
     * @param x
     * @param y
     * @param width
     * @param height
     */
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {

        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;

        GL gl = drawable.getGL();

        if (height == 0)
          height = 1;    // to avoid division by 0 in aspect ratio below       

        gl.glMatrixMode(GL.GL_MODELVIEW);
        
    }

    /**
     * Not implemented in JOGL yet
     * @param drawable
     * @param modeChanged
     * @param deviceChanged
     */
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * Wrote this method to prove FPSAnimator was doing its job
     */
    public void calculateFPS()
    {     
        if((System.nanoTime() - secondsCounter) >= 1000000000)
        {
            secondsCounter = System.nanoTime();         
           
            top.setTitle("3D Stereo Pair Viewer - FPS: "+frameCount); //display the fps in the jframe title
            fps=frameCount;
            frameCount = 0;
        }            
    }

    public void keyTyped(KeyEvent e) {
       
    }

    public void keyPressed(KeyEvent e) {
        //if left or right then change yRotate etc
        if(e.getKeyCode() == 37)
        {
            yLeft = true;
            
        }
        if(e.getKeyCode() == 39)
        {
            yRight = true;
        }
        if(e.getKeyCode() == 38)
        {
            xUp = true;
        }
        if(e.getKeyCode() == 40)
        {
            xDown = true;
        }

        if(e.getKeyChar() == 'm')
        {
            wireframeMode = !wireframeMode;//toggle rendering modes
        }

        if(e.getKeyCode() == 61)
        {
             interocularDistance +=0.05;
        }
        if(e.getKeyCode() == 45)
        {            
            interocularDistance -=0.05;            
            
        }
         if(e.getKeyCode() == 107)

        {

            zForward = true;

        }

        if(e.getKeyCode() == 109)

        {

            zBackward = true;

        }
        
    
    }
   

    public void keyReleased(KeyEvent e) {

        if(e.getKeyCode() == 37)
        {
            yLeft = false;

        }
        if(e.getKeyCode() == 39)
        {
            yRight = false;
        }
        if(e.getKeyCode() == 38)
        {
            xUp = false;
        }
        if(e.getKeyCode() == 40)
        {
            xDown = false;
        }
         if(e.getKeyCode() == 107)

        {

            zForward = false;

        }

        if(e.getKeyCode() == 109)

        {

            zBackward = false;

        }
        
    }

   


}